<template>
  <div class="m-popover">
    <div ref="trigger" class="m-popover__trigger" @click="toggleVisible">
      <slot name="trigger"></slot>
    </div>

    <teleport to="body">
      <div
        v-if="visible"
        ref="popover"
        class="m-popover__content"
        :class="[`m-popover__content--${placement}`]"
        :style="contentStyle"
        @click.stop
      >
        <slot></slot>
        <div v-if="showArrow" class="m-popover__arrow" :class="[`m-popover__arrow--${placement}`]"></div>
      </div>
      <div v-if="visible" class="m-popover__mask" @click="close"></div>
    </teleport>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue';

const props = defineProps({
  // 弹出位置：top, bottom, left, right
  placement: {
    type: String,
    default: 'bottom',
    validator: (value) => ['top', 'bottom', 'left', 'right'].includes(value)
  },
  // 是否默认显示
  defaultVisible: {
    type: Boolean,
    default: false
  },
  // 触发方式：click, hover
  trigger: {
    type: String,
    default: 'click',
    validator: (value) => ['click', 'hover'].includes(value)
  },
  // 弹出内容偏移量
  offset: {
    type: Number,
    default: 8
  },
  // 是否显示箭头
  showArrow: {
    type: Boolean,
    default: true
  }
});

const emit = defineEmits(['visible-change']);

const visible = ref(props.defaultVisible);
const trigger = ref(null);
const popover = ref(null);
const contentStyle = ref({});

// 切换显示状态
const toggleVisible = () => {
  visible.value = !visible.value;
  emit('visible-change', visible.value);
  if (visible.value) {
    // 使用nextTick确保DOM更新后再定位
    nextTick(() => {
      updatePosition();
    });
  }
};

// 关闭弹出窗
const close = () => {
  visible.value = false;
  emit('visible-change', false);
};

// 更新弹出位置
const updatePosition = () => {
  if (!trigger.value || !popover.value) return;

  const triggerRect = trigger.value.getBoundingClientRect();
  const popoverRect = popover.value.getBoundingClientRect();
  const screenWidth = window.innerWidth;
  const screenHeight = window.innerHeight;

  const style = {};

  switch (props.placement) {
    case 'top':
      style.top = `${triggerRect.top - popoverRect.height - props.offset}px`;
      style.left = `${triggerRect.left + triggerRect.width / 2 - popoverRect.width / 2}px`;
      // 检查是否超出屏幕顶部
      if (parseInt(style.top) < 0) {
        style.top = `${triggerRect.bottom + props.offset}px`;
      }
      break;
    case 'bottom':
      style.top = `${triggerRect.bottom + props.offset}px`;
      style.left = `${triggerRect.left + triggerRect.width / 2 - popoverRect.width / 2}px`;
      // 检查是否超出屏幕底部
      if (parseInt(style.top) + popoverRect.height > screenHeight) {
        style.top = `${triggerRect.top - popoverRect.height - props.offset}px`;
      }
      break;
    case 'left':
      style.top = `${triggerRect.top + triggerRect.height / 2 - popoverRect.height / 2}px`;
      style.left = `${triggerRect.left - popoverRect.width - props.offset}px`;
      // 检查是否超出屏幕左侧
      if (parseInt(style.left) < 0) {
        style.left = `${triggerRect.right + props.offset}px`;
      }
      break;
    case 'right':
      style.top = `${triggerRect.top + triggerRect.height / 2 - popoverRect.height / 2}px`;
      style.left = `${triggerRect.right + props.offset}px`;
      // 检查是否超出屏幕右侧
      if (parseInt(style.left) + popoverRect.width > screenWidth) {
        style.left = `${triggerRect.left - popoverRect.width - props.offset}px`;
      }
      break;
  }

  // 确保左右不超出屏幕
  if (parseInt(style.left) < 0) {
    style.left = '0px';
  }
  if (parseInt(style.left) + popoverRect.width > screenWidth) {
    style.left = `${screenWidth - popoverRect.width}px`;
  }

  // 确保上下不超出屏幕
  if (parseInt(style.top) < 0) {
    style.top = '0px';
  }
  if (parseInt(style.top) + popoverRect.height > screenHeight) {
    style.top = `${screenHeight - popoverRect.height}px`;
  }

  contentStyle.value = style;
};

// 点击外部关闭
const handleClickOutside = (e) => {
  if (
    visible.value &&
    trigger.value &&
    !trigger.value.contains(e.target) &&
    popover.value &&
    !popover.value.contains(e.target)
  ) {
    close();
  }
};

// 监听滚动和调整大小事件，更新位置
const handleScrollResize = () => {
  if (visible.value) {
    updatePosition();
  }
};

onMounted(() => {
  document.addEventListener('click', handleClickOutside);
  window.addEventListener('scroll', handleScrollResize);
  window.addEventListener('resize', handleScrollResize);

  // 如果是hover触发
  if (props.trigger === 'hover' && trigger.value) {
    trigger.value.addEventListener('mouseenter', () => {
      visible.value = true;
      emit('visible-change', true);
      updatePosition();
    });
    trigger.value.addEventListener('mouseleave', () => {
      visible.value = false;
      emit('visible-change', false);
    });
  }
});

onUnmounted(() => {
  document.removeEventListener('click', handleClickOutside);
  window.removeEventListener('scroll', handleScrollResize);
  window.removeEventListener('resize', handleScrollResize);
});
</script>

<style scoped>
.m-popover {
  display: inline-block;
  position: relative;
}

.m-popover__trigger {
  display: inline-block;
  cursor: pointer;
}

.m-popover__mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.1);
  z-index: 999;
}

.m-popover__content {
  position: fixed;
  background-color: #fff;
  border-radius: 0;
  padding: 12px;
  z-index: 1000;
  transition: opacity 0.2s, transform 0.2s;
  opacity: 0;
  transform: scale(0.95);
}

.m-popover__content--top,
.m-popover__content--bottom {
  min-width: 100px;
  max-width: 300px;
}

.m-popover__content--left,
.m-popover__content--right {
  min-height: 40px;
}

.m-popover__content--top {
  transform-origin: bottom center;
}

.m-popover__content--bottom {
  transform-origin: top center;
}

.m-popover__content--left {
  transform-origin: right center;
}

.m-popover__content--right {
  transform-origin: left center;
}

.m-popover__content:not([style*="display: none"]) {
  opacity: 1;
  transform: scale(1);
}

.m-popover__arrow {
  position: absolute;
  width: 0;
  height: 0;
  border-style: solid;
  background: transparent;
}

.m-popover__arrow--top {
  bottom: -8px;
  left: 50%;
  margin-left: -8px;
  border-width: 8px 8px 0 8px;
  border-color: #fff transparent transparent transparent;
}

.m-popover__arrow--bottom {
  top: -8px;
  left: 50%;
  margin-left: -8px;
  border-width: 0 8px 8px 8px;
  border-color: transparent transparent #fff transparent;
}

.m-popover__arrow--left {
  right: -8px;
  top: 50%;
  margin-top: -8px;
  border-width: 8px 0 8px 8px;
  border-color: transparent transparent transparent #fff;
}

.m-popover__arrow--right {
  left: -8px;
  top: 50%;
  margin-top: -8px;
  border-width: 8px 8px 8px 0;
  border-color: transparent #fff transparent transparent;
}
</style>